package com.ruoyi.config;


import com.ruoyi.platform.manager.AsyncManager;
import com.ruoyi.platform.manager.factory.AsyncFactory;
import com.ruoyi.platform.system.domain.SysOperLog;
import com.ruoyi.platform.utils.SecurityUtils;
import com.ruoyi.platform.utils.ServletUtils;
import com.ruoyi.platform.utils.ThreadMsgUtil;
import com.ruoyi.platform.utils.ip.AddressUtils;
import com.ruoyi.platform.utils.ip.IpUtils;
import jodd.io.NetUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Date;

@Component
@Slf4j
public class LogClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ClientHttpResponse response = execution.execute(request, body);

        stopWatch.stop();
        StringBuilder resBody = new StringBuilder();
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(),
                Charset.forName("UTF-8")))) {
            String line = bufferedReader.readLine();
            while (line != null) {
                resBody.append(line);
                line = bufferedReader.readLine();
            }
        }
        //当然图片、文件一类的就可以省了，打出日志没啥用处，此处的业务逻辑随意撸了，比如header头信息类似于  Accept 、Accept-Encoding 、Accept-Language、Connection 等等
        if (request.getHeaders().getContentType() != null && request.getHeaders().getContentType().includes(MediaType.MULTIPART_FORM_DATA)) {
            body = new byte[]{};
        }

        RestLog restLog = RestLog.builder().costTime(stopWatch.getLastTaskTimeMillis()).headers(request.getHeaders()).method(request.getMethodValue())
                .reqUrl(request.getURI().toString()).reqBody(new String(body, Charset.forName("UTF-8"))).resBody(resBody.toString()).resStatus(response.getRawStatusCode()).build();
        SysOperLog operLog = new SysOperLog();
        operLog.setOperatorType(3);
        operLog.setStatus( (restLog.getResStatus() == 200) ? 0 : 1);
        operLog.setJsonResult(restLog.getResBody());
        operLog.setMethod(restLog.getMethod());
        operLog.setOperUrl(restLog.getReqUrl());
        log.info("请求参数:{}",restLog.getReqBody());
        operLog.setOperParam(restLog.getReqBody());
        operLog.setTitle(ThreadMsgUtil.getPtTypeTl());
        String operationName = "无用户登陆";
        try {
            operationName =  SecurityUtils.getUsername();
        }catch (Exception e){
            log.error("执行业务时，获取用户名失败");
        }
        operLog.setOperName(operationName);
        try {
            // 登陆的时候，可能获取不到Request
            operLog.setOperIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        }catch (Exception e){
            operLog.setOperIp(NetUtil.LOCAL_IP);
        }

        operLog.setOperTime(new Date());
        operLog.setBusinessType(13);
        operLog.setRequestMethod(restLog.getMethod());
        operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
        // 保存数据库
        AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
        log.info("执行NFT业务：{}",restLog.toString());
        return response;
    }

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @SuppressWarnings("rawtypes")
    private static class RestLog {
        private String reqUrl;
        private String method;
        private HttpHeaders headers;
        private String reqBody;
        private String resBody;
        private long costTime;
        private int resStatus;
    }

}

